/*********************************************************************************************************
*	Projeto Final: SCC-0143 - Programação Concorrente						
*	Professor: Julio Cezar Estrella
*	Integrantes: Cesar Augusto Sales Gomes
*		     Matheus Salgado Boscariol
*	             Robson Pereira ALeixo
*
*	Gerador de Palavras:
*		Gerar palavras com tamanhos até 5 caracteres e verificar se elas estão em um arquivo    		
*
**********************************************************************************************************/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "mpi.h"
#include "loadArchive.h"

/*
	objetivo: verifica se a palavra existe, caso sim retorna -1, caso contrário retorna 0
	parametro w: palavra que será procurada
	parametro v: vetor com as palavras lidas do arquivo
	parametro inicio: posição inicial de v
	parametro fim: posição final de v
*/
int existWord(char *w, char **v, int inicio, int fim){
	
	int meio = 0;
	if(fim == 0){
		return 0;
	}else
	{
			fim = fim-1;
			if(strcmp(w,v[fim]) > 0)
			{
					return fim+1;
			 }else
			 { 
				if(strcmp(w,v[inicio]) < 0){
					
					return 0;
				}else
				{
					while (inicio <= fim) 
					{	
						meio = (inicio + fim)/2;

						if (strcmp(w,v[meio]) == 0){
								return -1;
						}else
						{
							if(inicio == fim)
							{
								if(strcmp(w,v[inicio]) < 0)
									return meio;
								else
									return meio+1;
							}else
							{
								if(strcmp(w,v[inicio]) < 0 && (fim == inicio+1))
								{
									return meio;
								}else
								{
									if(strcmp(w,v[fim]) > 0 && (fim == inicio+1))
									 	return fim+1;
									else
									{
										
										if (strcmp(w,v[meio]) < 0){					       
											fim = meio-1;
										}else
										{	
											if(strcmp(w,v[meio]) > 0)
											{
												inicio = meio+1;
											}
										}
											
									}
								}	
							}	
						}
					}
				}
				return meio+1;
			}
		}
}

/*
	insere a nova palavra de forma ordenada
	parametro w: string a ser inserida
	parametro v: vetor da estrutura a qual a palavra será inserida
	parametro insert: posição no vetor a qual ela será inserida
	parametro tam: tamanho do vetor onde ela será inserida
*/
void insertWord(char *w, char **v, int insert, int tam){

	int i;
	
	if(tam == 0){
		strcpy(v[tam],w);
	}else{
		tam = tam+1;
		if(insert == tam){
			strcpy(v[tam+1],w);
		 }else{	
			/*move as antigas palavras em uma posição*/
			for(i=tam ; i > insert ; i--)
				strcpy(v[i],v[i-1]);
			/*insere a nova palavra*/	
			strcpy(v[insert], w);
		}
	}
	

}
/*
	objetivo: alocar as variaveis da estrutura WFF
*/
void alocaWFF(WordFromFile *WFF){

	int i,j;
	WFF->tamWord = 0;
	WFF->size = (int*)calloc(tamArrayHead,sizeof(int));
	WFF->numPorVetorAteCinco = (int*)calloc(tamArrayHead,sizeof(int));
	for(i=0 ; i<tamArrayHead ; i++){
		WFF->size[i] = 0;
		WFF->numPorVetorAteCinco[i] = 0;
	}
	printf("alocando estrutura...\n");
	WFF->text = (char***) calloc(tamArrayHead,sizeof(char**));	
		for(i=0; i < tamArrayHead; i++){
			WFF->text[i] = (char**)calloc(qtdWordPorPos,sizeof(char*));
		}
		for(i=0 ; i < tamArrayHead; i++){
			for(j=0 ; j < qtdWordPorPos; j++){
				WFF->text[i][j] = (char*)calloc(sizeWord,sizeof(char));
			}
		}
	printf("estrutura alocada!\n");
}
/*
	soma os valores Ansi das letras de uma palavra
*/
int valorAsciiWord(char *toke){

	int wordTam;
	wordTam = strlen(toke);

	if(wordTam > 4)
		wordTam = 4;/*para selecionar melhor as palavras grandes, fazendo as que possuem os quatro primeiros caracteres iguais juntas*/
	int i, tam;
	for(i=0 ; i<wordTam ; i++){
		tam += toke[i];
	}
	return tam;
}
/*
	Objetivo: deixa todas as letras em forma minuscula
*/
void tratarText(char *textFile){

	int i;
	for(i=0 ; i<strlen(textFile) ; i++){
		if(textFile[i] > 64 && textFile[i] < 91){
			textFile[i] = (char)(textFile[i] + 32); 
		}
	}

}
/*
	Objetivo: calcula o tamanho do arquivo
*/
int tamArquivo(FILE *f){
        
        int size = 0;
        fseek(f,0,SEEK_END);
        size = ftell(f);
        fseek(f,0,SEEK_SET);
        return size;

}
/*
	Objetivo: Carrega arquivo e armazena na estrutura

*/
void loadFile(WordFromFile *WFF){

	char *textFile; /*arquivo inteiro*/
	char *toke; /*palavra do arquivo*/
	int pos; /*posição no hash*/
	int insertPosition;/*posição para ser inserida no vetor*/
	int ansiWord; /*pega o valor ansi da palavra*/
	int sizeSend; /*tamanho do vetor que será enviado para busca como posição de fim*/
	int tamFile; /*tamanho do arquivo*/
	
	FILE *data;

	data = fopen("palavras.txt","r");
	
	if(data == NULL)
		printf("Arquivo não pode ser aberto!\n");
	else{
		
		/*alocando o arquivo inteiro para buffer*/
		tamFile = tamArquivo(data);
		textFile = (char*)malloc(tamFile*sizeof(char));
		
		fgets(textFile,tamFile,data);

		/*recebe a primeira palavra*/
		toke = strtok (textFile, "\n\r-, ");
		
		/*leitura do arquivo até o EOF*/
		while(toke != NULL){
			
			tratarText(toke);

			ansiWord = valorAsciiWord(toke);
	
			/*calcula a posição em que ele será armazenado*/
			pos = (int)ansiWord%tamArrayHead;
			sizeSend = WFF->size[pos];

			/*verifica se a letra já foi armazenada, caso não exista ele armazena em WFF na posição insertPosition*/
			insertPosition = existWord(toke, WFF->text[pos], 0, sizeSend);
			/*printf("[%s]", toke);*/
			if(insertPosition >= 0){
				insertWord(toke, WFF->text[pos], insertPosition, sizeSend);
				if(strlen(toke) <= 5)
					WFF->numPorVetorAteCinco[pos]++;
				/*somando uma unidade para onde a palavra foi alocada e na contagem total*/				
				WFF->tamWord++;
				WFF->size[pos]++;
					
			}
			
			toke = strtok (NULL,"$()#/&\n\r-,1234567890.'% ");
               	}

	}
	printf("\nNumero de palavras inseridas: %d\n", WFF->tamWord);		
	fclose(data);
}
/*
	Objetivo: imprime a estrutura onde estao sendo armazenado as palavras
*/
void imprime(WordFromFile *WFF){

	FILE *hash;
	hash = fopen("hash.txt","w+");

	int i,j;
	for(i=0 ; i < tamArrayHead; i++){
		fprintf(hash,"linha[%d]:\n",i);
		for(j=0 ; j < WFF->size[i]; j++)
			fprintf(hash,"%s | ", WFF->text[i][j]);
		fprintf(hash,"\n");
	}
	printf("\nNumero de palavras inseridas: %d\n", WFF->tamWord);

	fclose(hash);
}
